package org.kernely.stream;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import org.kernely.security.persistence.User;
import org.kernely.stream.dao.MessageDAO;
import org.kernely.stream.dao.StreamDAO;
import org.kernely.stream.persistence.Message;
import org.kernely.stream.persistence.Stream;
import org.kernely.stream.service.KernelyStreamService;
import org.kernely.stream.service.StreamFilter;
import org.osgi.framework.BundleEvent;

public class KernelyStreamServiceImpl implements KernelyStreamService{

	private static HashMap<String, HashSet<String>> allBundlesStreams = new HashMap<String, HashSet<String>>();
	private ArrayList<StreamFilter> registeredFilters = new ArrayList<StreamFilter>();

	/**
	 * @see org.kernely.stream.service.KernelyStreamService#postOnBundleStream(String, String, String)
	 */
	public void postOnBundleStream(String uniqueId, String title, String content){
		if (content != null && content != "" ){
			Stream stream = StreamDAO.getInstance().findStream(Stream.CATEGORY_BUNDLES,uniqueId);

			Message newMessage = new Message();
			if (content.length() > 140){
				content = content.substring(0, 140);
			}
			newMessage.setContent(content);

			newMessage.setUser(null); // User null is the system.
			java.sql.Date date = new java.sql.Date(new Date().getTime());
			newMessage.setDate(date);
			newMessage.setStream(stream);
			MessageDAO.getInstance().saveMessage(newMessage);
		}		
	}

	/**
	 * @see org.kernely.stream.service.KernelyStreamService#createBundleStream(String, String, String)
	 */
	public void createBundleStream(String bundleSymbolicName, String streamTitle, String uniqueId) {

		StreamDAO sdao = StreamDAO.getInstance();

		// Creates the stream only if it doesn't exists.
		if (sdao.findStream(Stream.CATEGORY_BUNDLES, uniqueId) == null){
			Stream newStream = new Stream();
			newStream.setTitle(streamTitle);
			newStream.setCategory(Stream.CATEGORY_BUNDLES);
			newStream.setMessages(new HashSet<Message>());
			newStream.setRedactors(new HashSet<User>());
			newStream.setSubscriptors(new HashSet<User>());
			newStream.setUid(uniqueId);
			StreamDAO.getInstance().saveStream(newStream);
		}

		// Add the stream to the map
		if (allBundlesStreams.containsKey(bundleSymbolicName)){
			System.out.println("ADD INTO THE MAP: "+bundleSymbolicName);
			allBundlesStreams.get(bundleSymbolicName).add(uniqueId);
		} else {
			HashSet<String> set = new HashSet<String>();
			set.add(uniqueId);
			allBundlesStreams.put(bundleSymbolicName, set);
		}
	}

	/**
	 * @see org.kernely.stream.service.KernelyStreamService#createStream(String, String)
	 */
	public String createStream(String title, String category) {
		Stream newStream = new Stream();
		UUID uniqueId = UUID.randomUUID();
		newStream.setTitle(title);
		newStream.setCategory(category);
		newStream.setUid(uniqueId.toString());
		StreamDAO.getInstance().saveStream(newStream);

		return uniqueId.toString();
	}

	/**
	 * Warn the service about a change in a bundle state.
	 * This function is used by the Activator of the StreamBundle, to lock/unlock messages from stopped/started bundles.
	 * @param bundleSymbolicName The symbolic name of the bundle which state changed.
	 * @param eventType The type of the changed (using BundleEvent constants).
	 */
	public static void bundleStateChanged(String bundleSymbolicName, int eventType){
		StreamDAO sdao = StreamDAO.getInstance();
		// Lock all the streams if the bundle is stopped.
		int lockValue = 0;
		if (eventType == BundleEvent.STOPPED){
			lockValue = 1;
		} else if (eventType == BundleEvent.STARTED){
			lockValue = 0;
		}

		if (allBundlesStreams.containsKey(bundleSymbolicName)){
			Set<String> streamsId = allBundlesStreams.get(bundleSymbolicName);
			for (String streamId : streamsId){
				Stream stream = sdao.findStream(Stream.CATEGORY_BUNDLES, streamId);
				stream.setLocked(lockValue);
				sdao.updateStream(stream);
			}
		}
	}

	/**
	 * @see org.kernely.stream.service.KernelyStreamService#registerStreamFilter(org.kernely.stream.service.StreamFilter)
	 */
	public void registerStreamFilter(StreamFilter filter) {
		this.registeredFilters.add(filter);
	}

	/**
	 * @see org.kernely.stream.service.KernelyStreamService#applyStreamFilters(java.lang.String)
	 */
	public String applyStreamFilters(String message) {
		String result = message;
		for(StreamFilter sf : registeredFilters){
			result = sf.applyFilter(result);
		}
		return result;
	}

	/**
	 * @see org.kernely.stream.service.KernelyStreamService#registerStreamFilter(org.kernely.stream.service.StreamFilter, int)
	 */
	public void registerStreamFilter(StreamFilter filter, int priority) {
		this.registeredFilters.add(priority, filter);	
	}



}
